package pwd.allen.util.mock.mvc;

import cn.hutool.json.JSONUtil;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import pwd.allen.config.MainConfig;
import pwd.allen.service.MyService;
import pwd.allen.web.config.WebConfig;
import pwd.allen.web.controller.MyController;
import pwd.allen.web.filter.MyFilter;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * 使用真正的spring容器模拟mvc
 * @author 门那粒沙
 * @create 2020-02-03 13:26
 **/
@WebAppConfiguration
@RunWith(SpringRunner.class)
@ContextHierarchy({
        @ContextConfiguration(classes = {MainConfig.class, WebConfig.class})
//        , @ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/dispatcherServlet-servlet.xml")
})
public class MockMvcTest1 {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Autowired
    private MyController myController;

    @Before
    public void before() {
        //初始化mock对象
        MockitoAnnotations.initMocks(this);

        // 构建MockMvc模拟
        ConfigurableMockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(wac);

        //使用Mockito模拟下MyService服务依赖 这里用不了springboot的@MockBean，只能先这样了
        MyService myService = Mockito.spy(MyService.class);
        ReflectionTestUtils.setField(myController, "myService", myService);

        // 设置默认请求属性
        mockMvcBuilder.defaultRequest(post("/")
//                .contextPath("/pwd-web")  // 这个设置了后好像后面的请求都要以/pwd-web开头才行
                .header("token", "test"));

        mockMvc = mockMvcBuilder.build();
    }

    /**
     * 测试get请求
     * @throws Exception
     */
    @Test
//    @Ignore
    public void mockGet() throws Exception {
        String name = "pwd";
        mockMvc.perform(get("/my/param/{name};id=1,2", name)
                .param("date", "2019-08-1")
                .param("error", "3"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$.name").value("pwd")) // 检验返回的json字符串的name属性
                .andDo(MockMvcResultHandlers.print()); // 打印返回结果
    }

    /**
     * 测试post请求
     * @throws Exception
     */
    @Test
//    @Ignore
    public void mockPost() throws Exception {
        String name = "pwd";
        mockMvc.perform(post("/my/requestBody")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(JSONUtil.createObj().set("name", "pwd").set("param", "test").toString()))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$.name").value("pwd")) // 检验返回的json字符串的name属性
                .andDo(MockMvcResultHandlers.print()); // 打印返回结果
    }

    /**
     * 测试上传文件
     * @throws Exception
     */
    @Test
    public void mockUpload() throws Exception {
        String filePath = "db.properties";
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders
                .multipart("/my/upload")
                .file(new MockMultipartFile("file", filePath, "text/plain", new ClassPathResource(filePath).getInputStream())))
                .andExpect(status().isOk())
                .andReturn();
        try {
            String contentAsString = mvcResult.getResponse().getContentAsString();
            System.out.println(contentAsString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
